package com.zhengshang.common.oss;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.zhengshang.common.utils.DateUtils;
import com.zhengshang.common.utils.StringUtils;
import com.zhengshang.common.utils.uuid.IdUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author HY
 * @version 1.0.0
 * @ClassName OssUtils.java
 * @Description TODO
 * @createTime 2021年04月08日 18:04
 */
public class OssUtils {

    private final static Logger logger = LoggerFactory.getLogger(OssUtils.class);

    /**
     * 密钥ID
     */
    private static final String ACCESS_KEY_ID = "LTAI5tDPypJKiptT45XnA8ag";
    /**
     * 密钥Secret
     */
    private static final String ACCESS_KEY_SECRET = "nF1R0HT7XhtXjBuohIuwrrh5OEnC5E";
    /**
     * bucketName
     */
    private static final String BUCKET_NAME = "youhuiniu";
    /**
     * Endpoint（地域节点）
     */
    private static final String ENDPOINT = "http://oss-cn-beijing.aliyuncs.com";
    /**
     * 分隔符
     */
    private static final String SEPARATOR = "/";
    /**
     * Bucket 域名
     */
    public static final String BUCKET_DOMAIN = "https://youhuiniu.oss-cn-beijing.aliyuncs.com/";
    /**
     * 文件类型：头像
     */
    public static final String FILE_TYPE_AVATAR = "avatar";
    /**
     * 文件类型：file
     */
    public static final String FILE_TYPE_FILE = "file";
    /**
     * 文件类型：二维码
     */
    public static final String FILE_TYPE_QRCODE = "qrcode";
    /**
     * 文件类型：视频
     */
    public static final String FILE_TYPE_VIDEO = "video";
    /**
     * 文件类型：线上教育
     */
    public static final String FILE_TYPE_EDUCATION = "education";
    /**
     * 文件类型：图片
     */
    public static final String FILE_TYPE_IMAGE = "image";
    /**
     * 文件类型：APK
     */
    public static final String FILE_TYPE_APK = "apk";

    public static final long MAX_PART_SIZE = 5 * 1024 * 1024;

    public static final long MAX_COPY_PART_SIZE = 1 * 1024 * 1024 * 1024;

    public static List<String> listObjectV2(String keyPrefix){
        // 指定每页200个文件。
        final int maxKeys = 200;
        // 指定前缀。
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        String nextMarker = "1";
        ObjectListing objectListing;
        List<String> objectIDList = new ArrayList<>();
        do {
            objectListing = ossClient.listObjects(new ListObjectsRequest(BUCKET_NAME).
                    withPrefix(keyPrefix).withMarker(nextMarker).withMaxKeys(maxKeys));
            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
            for (OSSObjectSummary s : sums) {
                if (s.getKey().indexOf(".") > -1) {
//                    System.out.println("\t" + s.getKey());
                    objectIDList.add(s.getKey());
                }
            }

            nextMarker = objectListing.getNextMarker();

        } while (objectListing.isTruncated());
        ossClient.shutdown();
        return objectIDList;
    }

    /**
     * 复制文件
     * @param oldKey
     * @param newKey
     * @return
     */
    public static String copy(String oldKey, String newKey){
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        //boolean isINoss = true;
        // 填写Bucket名称和Object完整路径。Object完整路径中不能包含Bucket名称。
        boolean found = ossClient.doesObjectExist(BUCKET_NAME, oldKey);
        if (!found) {
            logger.info("<OssUtils.copy>要复制的文件[{}]不存在", oldKey);
            return null;
        }

        SimplifiedObjectMeta objectMeta = ossClient.getSimplifiedObjectMeta(BUCKET_NAME, oldKey);
        if (objectMeta.getSize() < MAX_COPY_PART_SIZE) {
            return copySmallFile(ossClient, oldKey, newKey);
        } else {
            return copyBigFile(ossClient, oldKey, newKey, objectMeta.getSize());
        }
    }

    /**
     * 复制小文件
     * @param ossClient
     * @param oldKey
     * @param newKey
     * @return
     */
    public static String copySmallFile(OSS ossClient, String oldKey, String newKey){

        // 创建CopyObjectRequest对象。
        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(BUCKET_NAME, oldKey, BUCKET_NAME, newKey);

//        // 设置新的文件元信息。
//        ObjectMetadata meta = new ObjectMetadata();
//        meta.setContentType("text/txt");
//        copyObjectRequest.setNewObjectMetadata(meta);

        // 复制文件。
        CopyObjectResult result = ossClient.copyObject(copyObjectRequest);
        // 关闭OSSClient。
        ossClient.shutdown();
        return newKey;
    }

    /**
     * 复制大文件
     * @param ossClient
     * @param oldKey
     * @param newKey
     * @param contentLength
     * @return
     */
    public static String copyBigFile(OSS ossClient, String oldKey, String newKey, long contentLength){

        // 设置分片大小为10 MB。单位为字节。
        long partSize = 1024 * 1024 * 100;

        // 计算分片总数。
        int partCount = (int) (contentLength / partSize);
        if (contentLength % partSize != 0) {
            partCount++;
        }

        // 初始化拷贝任务。可以通过InitiateMultipartUploadRequest指定目标文件元信息。
        InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(BUCKET_NAME, newKey);
        InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
        String uploadId = initiateMultipartUploadResult.getUploadId();

        // 分片拷贝。
        List<PartETag> partETags = new ArrayList<PartETag>();
        for (int i = 0; i < partCount; i++) {
            // 计算每个分片的大小。
            long skipBytes = partSize * i;
            long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;

            // 创建UploadPartCopyRequest。可以通过UploadPartCopyRequest指定限定条件。
            UploadPartCopyRequest uploadPartCopyRequest =
                    new UploadPartCopyRequest(BUCKET_NAME, oldKey, BUCKET_NAME, newKey);
            uploadPartCopyRequest.setUploadId(uploadId);
            uploadPartCopyRequest.setPartSize(size);
            uploadPartCopyRequest.setBeginIndex(skipBytes);
            uploadPartCopyRequest.setPartNumber(i + 1);
            UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest);

            // 将返回的分片ETag保存到partETags中。
            partETags.add(uploadPartCopyResult.getPartETag());
        }

        // 提交分片拷贝任务。
        CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
                BUCKET_NAME, newKey, uploadId, partETags);
        ossClient.completeMultipartUpload(completeMultipartUploadRequest);

        // 关闭OSSClient。
        ossClient.shutdown();
        return newKey;
    }

    /**
     * 批量删除
     * @param objectIDList
     */
    public static void deleteFile(List<String> objectIDList){
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        // 删除文件。key等同于ObjectName，表示删除OSS文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(BUCKET_NAME).withKeys(objectIDList));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * @title 文件上传
     * @param type 文件类型
     * @updateTime 2021/4/9 16:17
     */
    public static JSONObject uploadFile(MultipartFile file, String type) {
        return uploadFile(file, type, null);
    }

    /**
     * @title 文件上传
     * @param type 文件类型
     * @param fileName 文件名称（带后缀名）
     * @updateTime 2021/4/9 16:17
     */
    public static JSONObject uploadFile(MultipartFile file, String type, String fileName) {

        JSONObject object = new JSONObject();
        String objectID = "";
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        try {
            // 如果该bucketName不存在，则创建
            if (!ossClient.doesBucketExist(BUCKET_NAME)) {
                ossClient.createBucket(BUCKET_NAME);
            }
            if (StringUtils.isBlank(fileName)) {
//                fileName = file.getOriginalFilename();
                fileName = IdUtils.simpleUUID() + "." + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
            }
            String path = type + SEPARATOR + DateUtils.datePath().replaceAll("/", SEPARATOR);
            objectID = path + SEPARATOR + fileName;
            if (fileName.indexOf(".jpg") > -1 || fileName.indexOf(".png") > -1) {
                ObjectMetadata objectMetadata = new ObjectMetadata();
                objectMetadata.setContentType("image/jpg");
                ossClient.putObject(BUCKET_NAME, objectID, file.getInputStream(), objectMetadata);
            } else {
                if (file.getSize() > MAX_PART_SIZE) {
                    MultipartUpload multipartUpload = new MultipartUpload(ossClient, objectID, BUCKET_NAME);
                    multipartUpload.sliceUploadToAliyun(file.getBytes(), file.getSize());
                } else {
                    ossClient.putObject(BUCKET_NAME, objectID, file.getInputStream());
                }
            }
            object.put("originalName", fileName);
            object.put("objectID", objectID);
            object.put("url", BUCKET_DOMAIN + objectID);
        } catch (Exception e) {
            e.printStackTrace();
            object = null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return object;
    }

    /**
     * @title 文件上传
     * @param file 文件
     * @param type 文件类型
     * @updateTime 2021/4/9 16:17
     */
    public static JSONObject uploadVideo(MultipartFile file, String type) {

        JSONObject object = new JSONObject();
        String objectID = "";
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        try {
            // 如果该bucketName不存在，则创建
            if (!ossClient.doesBucketExist(BUCKET_NAME)) {
                ossClient.createBucket(BUCKET_NAME);
            }
            String fileName = IdUtils.simpleUUID() + "." + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
            String path = type + SEPARATOR + DateUtils.datePath().replaceAll("/", SEPARATOR);
            objectID = path + SEPARATOR + fileName;
            if (file.getSize() > MAX_PART_SIZE) {
                logger.info("文件过大，开始分片上传。。。");
                MultipartUpload multipartUpload = new MultipartUpload(ossClient, objectID, BUCKET_NAME);
                multipartUpload.sliceUploadToAliyun(file.getBytes(), file.getSize());
            } else {
                ossClient.putObject(BUCKET_NAME, objectID, file.getInputStream());
            }
            object.put("originalName", fileName);
            object.put("objectID", objectID);
            object.put("url", BUCKET_DOMAIN + objectID);
        } catch (Exception e) {
            e.printStackTrace();
            object = null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return object;
    }

    /**
     * @title 文件上传
     * @param base64str 文件base64字符串
     * @param type 文件类型
     * @param fileName 文件名称（带后缀名）
     * @updateTime 2021/4/9 16:17
     */
    public static JSONObject uploadFile(String base64str, String type, String fileName) {

        JSONObject object = new JSONObject();
        String objectID = "";
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        try {
            // 如果该bucketName不存在，则创建
            if (!ossClient.doesBucketExist(BUCKET_NAME)) {
                ossClient.createBucket(BUCKET_NAME);
            }
            String path = type + SEPARATOR + DateUtils.datePath().replaceAll("/", SEPARATOR);
            objectID = path + SEPARATOR + fileName;
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] bytes = decoder.decodeBuffer(base64str);
            if (fileName.indexOf(".jpg") > -1 || fileName.indexOf(".png") > -1) {
                ObjectMetadata objectMetadata = new ObjectMetadata();
                objectMetadata.setContentType("image/jpg");
                ossClient.putObject(BUCKET_NAME, objectID, new ByteArrayInputStream(bytes), objectMetadata);
            } else {
                ossClient.putObject(BUCKET_NAME, objectID, new ByteArrayInputStream(bytes));
            }
            object.put("originalName", fileName);
            object.put("objectID", objectID);
            object.put("url", BUCKET_DOMAIN + objectID);
        } catch (Exception e) {
            e.printStackTrace();
            object = null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return object;
    }

    public static String getPrefix(String objectID){
        return objectID.substring(objectID.lastIndexOf(".") + 1);
    }

    public static String newFileName(String objectID){
        return IdUtils.simpleUUID() + "." + getPrefix(objectID);
    }

    public static String getVideoName(String objectID){
        String[] paths = objectID.split("/");
        String fileName = paths[paths.length - 1];
        return fileName.substring(0, fileName.lastIndexOf("."));
    }
}
